<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
<ul class="list">
    <li>li 1</li>
    <li>li 2</li>
    <li>li 3</li>
    <li>li 4</li>
</ul>    

<script>
// 闭包分为：无效闭包和有效闭包

// 无效闭包：函数嵌套，内部函数引用外部函数的变量或形参
/* function outer(n){
    var x = 2;// 局部变量
    function inner(){
        x++;
        console.log( x );// 引用外部变量，会形成闭包

        // console.log( n );// 引用外部形参，会形成闭包

        // console.log( 123 );//不会形成闭包
    }
    inner();
}
outer();// 3
outer();// 3
outer();// 3 */


// 有效闭包：函数嵌套，内部函数引用外部函数的变量或形参，在外部保持对内部函数的引用，并且在外部调用内部函数
/* function outer(){
    var x = 2;
    function inner(){
        x++;
        console.log( x );
    }
    return inner;
}
var inner = outer();
inner();// 3
inner();// 4
inner();// 5

// outer()();// 3
// outer()();// 3
// outer()();// 3 */

// 函数嵌套，内部函数引用外部函数的变量或形参，在外部保持对内部函数的引用，并且在外部调用内部函数，此时内部函数和其上层执行上下文共同构成 闭包

// 闭包的作用：
// 1.延迟局部变量的生命周期
// 2.在全局可以操作局部变量

/* function outer(){
    var x = 2;
    return function (){// inner
        x++;
        console.log( x );
    }
}
var inner = outer();
inner();// 3
inner();// 4
inner();// 5 */

// 闭包应用场景
// 需求：打印点击的那个li的索引
var lis = document.querySelectorAll('.list li');
// for (var i = 0; i < lis.length; i++) {
//     lis[i].index = i;
//     lis[i].onclick = function (){
//         console.log( this.index );
//     }
// }

for (var i = 0; i < lis.length; i++) {
    (function (x){
        lis[x].onclick = function (){
            // 当事件触发时，事件处理函数是在全局调用
            console.log( x );// 引用外部函数的形参
        }
    })(i);
}


// 模块化
 (function (){
    var name = '张三';
    var sex = '男';
    var age = 23;
    var say = function (){
        console.log( '我叫'+name+'，今年'+age+'岁' );
    }
    window.say = say;
})();
say(); 

 var module = (function (){
    var name = '张三';
    var sex = '男';
    var age = 23;
    var say = function (){
        console.log( '我叫'+name+'，今年'+age+'岁' );
    }
    return {// module
        name: name,
        say: say
    }
})();
module.say(); 

// 闭包的缺点：容易造成内存泄漏，占用更多内存空间

// 如何避免闭包带来的问题？
// 1.能不用尽量不使用闭包
// 2.使用完之后解除引用关系
function outer(){
    var x = 2;
    return function (){// inner
        x++;
        console.log( x );
    }
}
var inner = outer();
inner();// 3
inner();// 4
inner();// 5
inner = null;// 解除引用关系
// inner();// 报错

</script>
</body>
</html>